﻿using DiyEFConfigurationBuilder.Obersver;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace DiyEFConfigurationBuilder
{
    internal class EFConfigurationProvider : ConfigurationProvider
    {
        private readonly EFConfigurationSource _source;
        private IDictionary<string, string> _dictionary;

        internal EFConfigurationProvider(EFConfigurationSource eFConfigurationSource)
        {
            _source = eFConfigurationSource;
            if (_source.ReloadOnChange)
            {
                EntityChangeObserver.Instance.Changed += EntityChangeObserverChanged;
            }
        }

        public override void Load()
        {
            DiyEFContext dbContext = _source.DBContext;
            if (_source.DBContext != null)
            {
                dbContext = _source.DBContext;
            }
            _dictionary = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            // https://stackoverflow.com/questions/38238043/how-and-where-to-call-database-ensurecreated-and-database-migrate
            // context.Database.EnsureCreated()是新的 EF 核心方法，可确保上下文的数据库存在。如果存在，则不执行任何操作。如果它不存在，则创建数据库及其所有模式，并确保它与此上下文的模型兼容
            dbContext.Database.EnsureCreated();
            var keyValueData = dbContext.DiyConfigs.ToDictionary(c => c.Key, c => c.Value);
            foreach (var item in keyValueData)
            {
                if (JsonHelper.IsJson(item.Value))
                {
                    var jsonDict = JsonConvert.DeserializeObject<Dictionary<string, Object>>(item.Value);
                    _dictionary.Add(item.Key, item.Value);
                    InitData(jsonDict);
                }
                else
                {
                    _dictionary.Add(item.Key, item.Value);
                }
            }
            Data = _dictionary;
        }

        private void InitData(Dictionary<string, object> jsonDict)
        {
            foreach (var itemval in jsonDict)
            {
                if (itemval.Value.GetType().ToString().Equals("Newtonsoft.Json.Linq.JObject"))
                {
                    Dictionary<string, object> reDictionary = new Dictionary<string, object>();
                    JObject jsonObject = (JObject)itemval.Value;
                    foreach (var VARIABLE in jsonObject.Properties())
                    {
                        reDictionary.Add((itemval.Key + ":" + VARIABLE.Name), VARIABLE.Value);
                    }
                    string key = itemval.Key;
                    string value = itemval.Value.ToString();
                    if (!string.IsNullOrEmpty(value))
                    {
                        _dictionary.Add(key, value);
                        InitData(reDictionary);
                    }
                }
                if (itemval.Value.GetType().ToString().Equals("System.String"))
                {
                    string key = itemval.Key;
                    string value = itemval.Value.ToString();
                    if (!string.IsNullOrEmpty(value))
                    {
                        _dictionary.Add(key, value);
                    }
                }
                if (itemval.Value.GetType().ToString().Equals("System.Boolean"))
                {
                    string key = itemval.Key;
                    string value = itemval.Value.ToString();
                    if (!string.IsNullOrEmpty(value))
                    {
                        _dictionary.Add(key, value);
                    }
                }
                if (itemval.Value.GetType().ToString().Equals("Newtonsoft.Json.Linq.JValue"))
                {
                    string key = itemval.Key;
                    string value = itemval.Value.ToString();
                    if (!string.IsNullOrEmpty(value))
                    {
                        _dictionary.Add(key, value);
                    }
                    if (JsonHelper.IsJson(itemval.Value.ToString()))
                    {
                        var rejsonObjects = JsonConvert.DeserializeObject<Dictionary<string, Object>>(itemval.Value.ToString());
                        InitData(rejsonObjects);
                    }
                }
                if (itemval.Value.GetType().ToString().Equals("Newtonsoft.Json.Linq.JArray"))
                {
                    string key = itemval.Key;
                    string value = itemval.Value.ToString();
                    _dictionary.Add(key, value);
                }
            }
        }
        private void EntityChangeObserverChanged(object sender, EntityChangeEventArgs e)
        {
            if (e.EntityEntry.Entity.GetType() != typeof(DiyConfig))
            {
                return;
            }

            //在将更改保存到底层数据库之前，稍作延迟以避免触发重新加载
            Thread.Sleep(_source.ReloadDelay);
            EFConfigurationBuilder.CreateEFConfiguration();
        }
    }
}
